package `02-lambada`

/**
 * lambda 的本质是函数，准确点是匿名函数
 */
fun main() {

    /**
     * 写法一：
     *
     * 声明+实现：
     * 公式：val/var 属性名 : (输入类型)->输出类型 = {参数1 参数类型,参数2 参数类型 -> 函数体}
     * 一般使用val，虽然是属性的样式，实际是函数，但是val/var属性意义仍有用。
     * =前是函数声明，=后是函数实现
     * 函数名是匿名，可以使用属性名访问
     * 函数体的最后一行是返回值，可以不加return
     * 在函数实现时，如果只有一个参数，可以不用写，在函数体中it代表参数。
     *
     * 使用：
     * 属性名()   调用函数
     * 属性名 打印的是函数，函数的输入和输出
     * 属性名 = 函数  和声明时同样的函数，会覆盖掉前面的函数
     */
    var method01:(Int)->String = {
        "当前数字是$it"
    }

    println(method01(1)) //打印结果 当前数字是1

    println(method01)  //打印出的是函数 (kotlin.Int) -> kotlin.String
    method01 = {value:Int-> "我是method01修改后的函数$value"} //会覆盖之前的函数

    println(method01(2))

    /**
     * 返回类型是Unit，因为最后一行println函数的返回类型是Unit
     */
    val method02:(Int)->Unit = {
        println("当前数字是$it")
    }
    method02(2)

    /**
     * 声明处写了函数输入输出类型，在实现处参数可以省略类型
     */
    val method03:(Int,Int)->String = {num1,num2->String
        "数字之和是$num1+$num2"
    }
    println(method03(1, 2))

    val method04:(Int,Int)->String = {_,num->String
        "method04，第一个参数没使用"
    }

    println(method04(0, 4))

    /**
     * 先声明，后实现
     */
    //声明
    val method05:()->Unit
    //实现
    method05 = {
        println("我是method05，先声明后实现")
    }
    method05()

    /**
     * lambda 实现扩展函数
     * 公式 val 属性名:类名.(输入类型)->输出类型 = {函数体}
     * Int.()->Unit  在Int类中添加一个匿名函数，匿名函数的没有输入参数，输出类型是Unit
     * 在{}函数实现体内 this代表类名实例本身。
     */
    val method06:Int.()->Unit = {
        println("我是lambda扩展函数，我的参数是$this")
    }
    1.method06()

    /**
     * 扩展函数
     * 扩展String类，添加一个函数，输入是String，输出是String
     */
    val method07:String.(String)->String = {str:String->String
        this+str;
    }
    println("第一字符串".method07("第二个字符串"))


    println("----------------------------------------------")

    /**
     * 输出是函数
     */
    /**
     * {}个函数 类型是()->Unit
     */
    println({}) //() -> kotlin.Unit

    /**
     * 函数的输出类型是函数
     *
     * 问题1：fun01函数的实现在哪？
     *
     * 公式：
     * fun 函数名():输出类型 = {输出函数实现体}
     */
    fun fun01():()->Unit = {
        println("我是输出函数")
    }
    println(fun01()) //() -> kotlin.Unit
    println(fun01()()) //我是输出函数

    //1个参数时it代表参数，最后一行是返回值
    fun fun02():(Int)->Int = {
        it
    }
    println(fun02()(2)) //2

    /**
     * fun03的输入类型是Int，输出类型是函数 (Int)->String
     * 在输出类型的函数实现体内，可以使用fun03的输入参数
     */
    fun fun03(num1:Int):(Int)->String = {num2->
        var total = num1+num2
        "$num1+$num2 = $total"
    }
    println(fun03(1)(2))

    /**
     * test01是个函数，是个参数中有函数的函数
     * 函数的类型是(Int,Int)->(Int,Int)->Unit 输入类型是(Int,Int)，输出类型是(Int,Int)->Unit
     * test01的输出函数的类型是(Int,Int)->Unit，输入类型是(Int,Int)，输出类型是Unit
     */
    //test01函数的声明
    val test01:(Int,Int)->(Int,Int)->Unit =
        //test01函数的实现
        fun (num1:Int,num2:Int):(Int,Int)->Unit
                //test01函数中参数函数的实现
                =   { num1:Int,num2:Int->
                        println("num1=$num1,num2=$num2")
                    }
    println(test01(66, 99)) //返回一个函数，类型是(Int,Int)->Unit
    println(test01(66, 99)(666, 999)) //Unit num1=666,num2=999

    println("")

    /**
     *  test01函数的变形
     */
    //test02函数声明
    val test02:(Int,Int)->(Int,Int)->Unit
    // test02函数的实现
    = {num1,num2->
        //test02函数实现体
        var num11 = num1+1
        var num22 = num2+1
        //test02输出函数的实现
        {num3,num4->
            var num33= num3+1
            var num44 = num4+1
            println("num1=$num11,num2=$num22,num3=$num33,num4=$num44")
        }
    }
    test02(1,2)(3,4)

    /**
     * test03是一个函数
     */
    val test03:(Int)->(Int)->(String)->(Boolean)->(String)->Unit
    //输入Int 输出(Int)->(String)->(Boolean)->(String)->Unit
    = {int1:Int->
        //输入Int 输出(String)->(Boolean)->(String)->Unit
        { int2:Int->
            //输入String 输出(Boolean)->(String)->Unit
            {str3:String->
                //输入 Boolean 输出(String)->Unit
                {boolean4:Boolean->
                    //输入String 输出Unit
                    {str5:String->Unit
                        println(1)
                    }
                }
            }
        }
    }
    test03(1)(2)("A")(true)("B")
}

/**
 * 普通函数，同Java
 * 输入 Int 输出String
 */
fun commonFun(num:Int):String{
    return "我是普通函数,我的输入是 $num"
}

fun funFun(str:(Int)->String):Unit{
    println(str)
}